package ldh.im.fxgui.controller;

import javafx.beans.InvalidationListener;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import ldh.im.fxbase.cell.FilterableTreeItem;
import ldh.im.fxbase.cell.ObjectTreeCell;
import ldh.im.fxbase.dao.ImDepartmentDao;
import ldh.im.fxbase.dao.ImGroupDao;
import ldh.im.fxbase.data.pojo.ImDepartment;
import ldh.im.fxbase.data.pojo.ImGroup;
import ldh.im.fxbase.data.pojo.ImGroupUser;
import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.controller.sub.GroupInfoController;
import ldh.im.fxgui.controller.sub.UserInfoController;
import ldh.im.fxgui.pojo.DepartmentUserItem;
import ldh.im.fxgui.pojo.GroupUserItem;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.fxgui.util.UserHeadImageUtil;

import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户管理
 */
public class UserTreeController extends BaseController implements Initializable {

    @FXML private TreeView<DepartmentUserItem> departmentTreeView;
    @FXML private TreeView<GroupUserItem> groupTreeView;
    @FXML private TextField searchTextField;
    @FXML private ToggleButton selectUser;
    @FXML private ToggleButton selectGroup;
    @FXML private Pane contentPane;

    private FilterableTreeItem<DepartmentUserItem> userRoot = buildDepartmentUserItemTreeItemRoot();
    private FilterableTreeItem<GroupUserItem> groupRoot = buildGroupUserTreeItemRoot();

    private ImDepartmentDao imDepartmentDao = BeanFactory.getInstance().getBean(ImDepartmentDao.class);
    private ImGroupDao imGroupDao = BeanFactory.getInstance().getBean(ImGroupDao.class);

    private RegionUtil.FxmlBean<Node, UserInfoController> userInfoFxmlBean = null;
    private RegionUtil.FxmlBean<Node, GroupInfoController> groupInfoFxmlBean = null;
    private ToggleGroup toggleGroup = new ToggleGroup();

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        selectUser.setToggleGroup(toggleGroup);
        selectGroup.setToggleGroup(toggleGroup);
        selectUser.setSelected(true);

        departmentTreeView.setRoot(userRoot);
        departmentTreeView.setShowRoot(false);
        departmentTreeView.setCellFactory(new ObjectTreeCell<>(d-> createTreeCell(d.getImUser(), d.getName())));

        groupTreeView.setRoot(groupRoot);
        groupTreeView.setShowRoot(false);
        groupTreeView.setCellFactory(new ObjectTreeCell<>(d-> createTreeCell(d.getImUser(), d.getName())));
        groupTreeView.setVisible(false);

        toggleGroup.selectedToggleProperty().addListener(l->{
            if (selectGroup.isSelected()) {
                groupTreeView.setVisible(true);
                departmentTreeView.setVisible(false);
            } else {
                departmentTreeView.setVisible(true);
                groupTreeView.setVisible(false);
            }
            loadData();
        });

        searchTextField.textProperty().addListener((ob, o, n)->{
            doSearch();
        });

        departmentTreeView.getSelectionModel().selectedItemProperty().addListener((InvalidationListener) l->{
            TreeItem<DepartmentUserItem> departmentUserItemTreeItem = departmentTreeView.getSelectionModel().getSelectedItem();
            if (departmentUserItemTreeItem == null) return;
            if (departmentUserItemTreeItem.getValue().getImUser() == null) return;
            if (userInfoFxmlBean == null) {
                userInfoFxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/sub/UserInfoPane.fxml"));
                userInfoFxmlBean.getController().setImUser(departmentUserItemTreeItem.getValue().getImUser());
                userInfoFxmlBean.getController().setMainController(mainController);
                contentPane.getChildren().clear();
                contentPane.getChildren().add(userInfoFxmlBean.getNode());
            } else {
                userInfoFxmlBean.getController().setImUser(departmentUserItemTreeItem.getValue().getImUser());
                contentPane.getChildren().clear();
                contentPane.getChildren().add(userInfoFxmlBean.getNode());
            }
        });

        groupTreeView.getSelectionModel().selectedItemProperty().addListener((InvalidationListener) l->{
            TreeItem<GroupUserItem> groupUserItemTreeItem = groupTreeView.getSelectionModel().getSelectedItem();
            if (groupUserItemTreeItem == null) return;
            if (groupUserItemTreeItem.getValue().getImUser() == null) return;
            if (groupInfoFxmlBean == null) {
                groupInfoFxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/sub/GroupInfoPane.fxml"));
            }
            groupInfoFxmlBean.getController().setImUser(groupUserItemTreeItem.getValue().getImUser());
            groupInfoFxmlBean.getController().setImGroup(groupUserItemTreeItem.getParent().getValue().getImGroup());
            groupInfoFxmlBean.getController().setMainController(mainController);
            contentPane.getChildren().clear();
            contentPane.getChildren().add(groupInfoFxmlBean.getNode());
        });

        loadData();
    }

    @FXML
    public void searchAct(ActionEvent actionEvent) {
        doSearch();
    }

    private void doSearch() {
        String filter = searchTextField.getText().trim();
        if(filter == null || filter.length() == 0) {
            if (selectUser.isSelected()) {
                userRoot.predicateProperty().set(s->true);
            }
            if (selectGroup.isSelected()) {
                groupRoot.predicateProperty().set(s->true);
            }
        } else {
            if (selectUser.isSelected()) {
                userRoot.predicateProperty().set(s -> {
                    boolean isValue = s.getName().contains(filter);
                    return isValue;
                });
            }
            if (selectGroup.isSelected()) {
                groupRoot.predicateProperty().set(s -> {
                    boolean isValue = s.getName().contains(filter);
                    return isValue;
                });
            }
        }
    }

    private void loadData() {
        ThreadPoolUtil.submit(()->{
            if (selectUser.isSelected()) {
                List<FilterableTreeItem<DepartmentUserItem>> filterableTreeItems = loadTreeDepartmentUserItems();
                FxThreadUtil.runLater(()->{
                    userRoot.getSourceChildren().setAll(filterableTreeItems);
                    if (filterableTreeItems.size() > 0) {
                        filterableTreeItems.get(0).setExpanded(true);
                    }
                    if (searchTextField.getText().length() > 0) {
                        doSearch();
                    }
                });
            }

            if (selectGroup.isSelected()) {
                List<FilterableTreeItem<GroupUserItem>> filterableTreeItems = loadTreeGroupUserItems();
                FxThreadUtil.runLater(()->{
                    groupRoot.getSourceChildren().setAll(filterableTreeItems);
                    if (filterableTreeItems.size() > 0) {
                        filterableTreeItems.get(0).setExpanded(true);
                    }
                    if (searchTextField.getText().length() > 0) {
                        doSearch();
                    }
                });
            }
        });
    }

    private Pane createTreeCell(ImUser user, String name) {
        HBox hBox = new HBox(5);
        hBox.getStyleClass().add("group-tree-cell");
        hBox.setAlignment(Pos.CENTER_LEFT);

        Label label = new Label(name);
        if (user != null) {
            ImageView imageView = new ImageView();
            imageView.setFitWidth(35);
            imageView.setFitHeight(35);
            String img = user.getHeadImg();
            if (img == null) img = user.getHeadImg();
            imageView.setImage(UserHeadImageUtil.getHeadImage(img));
            hBox.getChildren().add(imageView);
        } else {
            hBox.setPadding(new Insets(3, 0, 8, 0));
        }

        hBox.getChildren().add(label);
        return hBox;
    }

    private FilterableTreeItem<DepartmentUserItem> buildDepartmentUserItemTreeItemRoot() {
        ImDepartment imDepartment = new ImDepartment();
        imDepartment.setName("root");
        DepartmentUserItem departmentUserItem = new DepartmentUserItem(imDepartment);
        FilterableTreeItem<DepartmentUserItem> root = new FilterableTreeItem<>(departmentUserItem);
        return root;
    }

    private FilterableTreeItem<GroupUserItem> buildGroupUserTreeItemRoot() {
        ImGroup groupRoot = new ImGroup();
        groupRoot.setName("groupRoot");
        GroupUserItem groupUserItem = new GroupUserItem(groupRoot);
        FilterableTreeItem<GroupUserItem> groupRootItem = new FilterableTreeItem<>(groupUserItem);
        return groupRootItem;
    }

    private List<FilterableTreeItem<DepartmentUserItem>> loadTreeDepartmentUserItems() {
        List<FilterableTreeItem<DepartmentUserItem>> departmentUserItems = new ArrayList();
        try {
            List<ImDepartment> imDepartments = imDepartmentDao.getDepartments();
            List<ImUser> imUsers = ImCacheFactory.getInstance().getAllUsers();

            Map<String, List<ImUser>> userMap = imUsers.stream().filter(u->u.getDepartmentCode() != null).collect(Collectors.groupingBy(u->u.getDepartmentCode()));
            for(ImDepartment imDepartment : imDepartments) {
                if (!userMap.containsKey(imDepartment.getCode())) continue;
                Set<ImUser> imUserSet = userMap.get(imDepartment.getCode()).stream().collect(Collectors.toSet());
                imDepartment.setImUserSet(imUserSet);
            }
            List<ImDepartment> imDepartmentTree = buildTree(imDepartments);
            for(ImDepartment imDepartment : imDepartmentTree) {
                DepartmentUserItem departmentUserItem = new DepartmentUserItem(imDepartment);
                FilterableTreeItem<DepartmentUserItem> departmentUserItemFilterableTreeItem = new FilterableTreeItem<>(departmentUserItem);
                departmentUserItems.add(departmentUserItemFilterableTreeItem);
                addDepartmentChildren(imDepartment.getChildrenSet(), departmentUserItemFilterableTreeItem);
                addChildrenUser(imDepartment, departmentUserItemFilterableTreeItem);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return departmentUserItems;
    }

    private void addDepartmentChildren(Set<ImDepartment> imDepartmentSet, FilterableTreeItem<DepartmentUserItem> departmentUserItemFilterableTreeItem) {
        if (imDepartmentSet == null) return;
        for(ImDepartment imDepartment : imDepartmentSet) {
            DepartmentUserItem departmentUserItem = new DepartmentUserItem(imDepartment);
            FilterableTreeItem<DepartmentUserItem> departmentUserItemFilterableTreeItem2 = new FilterableTreeItem<>(departmentUserItem);
            departmentUserItemFilterableTreeItem.getSourceChildren().add(departmentUserItemFilterableTreeItem2);
            addDepartmentChildren(imDepartment.getChildrenSet(), departmentUserItemFilterableTreeItem2);
            addChildrenUser(imDepartment, departmentUserItemFilterableTreeItem2);
        }
    }

    private List<ImDepartment> buildTree(List<ImDepartment> imDepartments) {
        List<ImDepartment> roots = new ArrayList<>();
        Map<String, List<ImDepartment>> departmentChildrenMap = imDepartments.stream().filter(d->d.getParentCode() != null).collect(Collectors.groupingBy(k->k.getParentCode()));
        for(ImDepartment imDepartment : imDepartments) {
            if (imDepartment.getParentCode() == null) {
                roots.add(imDepartment);
            }
            List<ImDepartment> departments1 = departmentChildrenMap.get(imDepartment.getCode());
            if (departments1 != null) imDepartment.setChildrenSet(departments1.stream().collect(Collectors.toSet()));
        }
        return roots;
    }

    private void addChildrenUser(ImDepartment imDepartment, FilterableTreeItem<DepartmentUserItem> parentTreeItem) {
        if (imDepartment.getImUserSet() == null) return;
        for(ImUser imUser : imDepartment.getImUserSet()) {
            DepartmentUserItem departmentUserItem = new DepartmentUserItem(imUser);
            FilterableTreeItem<DepartmentUserItem> departmentUserItemFilterableTreeItem = new FilterableTreeItem<>(departmentUserItem);
            parentTreeItem.getSourceChildren().add(departmentUserItemFilterableTreeItem);
//            addDepartmentChildren(imDepartment.getChildrenSet(), departmentUserItemFilterableTreeItem);
        }
    }


    private List<FilterableTreeItem<GroupUserItem>> loadTreeGroupUserItems() {
        String userId = UiUtil.getLoginImUser().getUserId();
        List<FilterableTreeItem<GroupUserItem>> groupUserItems = new ArrayList();
        try {
            List<ImGroup> imGroups = imGroupDao.getDefaultGroups(userId);
            for(ImGroup imGroup : imGroups) {
                GroupUserItem groupUserItem = new GroupUserItem(imGroup);
                FilterableTreeItem<GroupUserItem> groupUserItemFilterableTreeItem = new FilterableTreeItem<>(groupUserItem);
                groupUserItems.add(groupUserItemFilterableTreeItem);
                addGroupChildren(imGroup.getGroupUserSet(), groupUserItemFilterableTreeItem);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return groupUserItems;
    }

    private void addGroupChildren(Set<ImGroupUser> groupUsers, FilterableTreeItem<GroupUserItem> groupUserItemFilterableTreeItem) {
        List<ImUser> users = groupUsers.stream().map(gu->ImCacheFactory.getInstance().getUser(gu.getUserId())).collect(Collectors.toList());
        for (ImUser imUser :users) {
            GroupUserItem userItem = new GroupUserItem(imUser);
            FilterableTreeItem<GroupUserItem> userItemFilterableTreeItem = new FilterableTreeItem<>(userItem);
            groupUserItemFilterableTreeItem.getSourceChildren().add(userItemFilterableTreeItem);
        }
    }

}
